package factorymethod.impl.factory;

import factorymethod.impl.product.Product;

/**
 * @ClassName: <code>Factory</code>, it is a abstract class.</br>
 * @Purpose: The is abstract class, it is the factory desgin model.
 * </br>工厂方法的主要功能是让父类[Factory]在不知道具体实现的情况下，完成自身的功能调用，
 * </br>而具体的实现延迟到子类[ConcreteFactory]来实现。
 * </br>这个是将主动权放弃，留给具体的子类， 有IoC/DI 类似！
 * 
 *          
 * Reference:  http://chjavach.iteye.com/blog/694864
 */
public abstract class Factory {
	
	/**
     * 创建Product的工厂方法
     * @return Product对象
     */
	// 工厂方法的主要功能是让父类[Factory]在不知道具体实现的情况下(1.具体的工厂; 2. 该工厂要生产的具体产品)，完成自身的功能调用，
	//而具体的实现延迟到子类[ConcreteFactory]来实现。
	// ！！！这个是将主动权放弃，留给具体的子类， 有IoC/DI 类似！
	//模式1：不带参数工厂方法
	public abstract Product factoryMethod();
    //模式2：带参数工厂方式; 传入任何实现了Product接口的实体类
	public abstract Product factoryMethod(Class<? extends Product> c);
    
    /**
     * 示例方法，实现某些功能的方法
     */
    public void someOperation() {
       //通常在这些方法实现中，需要调用工厂方法来获取Product对象
       Product product = factoryMethod();
    }
}
/*
 * 工厂方法  : 并不实现具体产品，而且选择创建具体产品
 */
/*
工厂方法      模式的优缺点 

可以在不知具体实现的情况下编程
    工厂方法模式可以让你在实现功能的时候，如果需要某个产品对象，只需要使用产品的接口即可，而无需关心具体的实现。选择具体实现的任务延迟到子类去完成。
更容易扩展对象的新版本
    工厂方法给子类提供了一个挂钩，使得扩展新的对象版本变得非常容易。比如上面示例的参数化工厂方法实现中，扩展一个新的导出Xml文件格式的实现，已有的代码都不会改变，
    只要新加入一个子类来提供新的工厂方法实现，然后在客户端使用这个新的子类即可。
    另外这里提到的挂钩，就是我们经常说的钩子方法(hook)，这个会在后面讲模板方法模式的时候详细点说明。
连接平行的类层次
    工厂方法除了创造产品对象外，在连接平行的类层次上也大显身手。这个在前面已经详细讲述了。
具体产品对象和工厂方法的耦合性
    在工厂方法模式里面，工厂方法是需要创建产品对象的，也就是需要选择具体的产品对象，并创建它们的实例，因此具体产品对象和工厂方法是耦合的。

3.6  思考工厂方法模式

1：工厂方法模式的本质
    工厂方法模式的本质：延迟到子类来选择实现。
    仔细体会前面的示例，你会发现，工厂方法模式中的工厂方法，在真正实现的时候，一般是先选择具体使用哪一个具体的产品实现对象，然后创建这个具体产品对象的示例，
    然后就可以返回去了。也就是说，工厂方法本身并不会去实现产品接口，具体的产品实现是已经写好了的，工厂方法只要去选择实现就好了。
   有些朋友可能会说，这不是跟简单工厂一样吗？
   确实从本质上讲，它们是非常类似的，具体实现上都是在“选择实现”。但是也存在不同点，简单工厂是直接在工厂类里面进行“选择实现”；
   而工厂方法会把这个工作延迟到子类来实现，工厂类里面使用工厂方法的地方是依赖于抽象而不是具体的实现，从而使得系统更加灵活，具有更好的可维护性和可扩展性。


*/